/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package meteocal.entityManager;

import java.security.Principal;
import java.util.Calendar;
import java.util.List;
import java.util.logging.Logger;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.persistence.EntityExistsException;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import meteocal.entity.Event;
import meteocal.entity.Notification;
import meteocal.entity.Users;

/**
 *
 * @author andrea
 */
@Stateless
public class NotificationManager {

    @PersistenceContext
    private EntityManager em;
    
    @Inject
    private UserManager um;
    
    @Inject
    private Principal principal;
    
    /**
     * Saves the notification in the database
     * @param notification
     */
    public void save(Notification notification){
        try{
            Calendar now = Calendar.getInstance();
            notification.setTimestamp(now);
            em.persist(notification);
        }
        catch(EntityExistsException e){
            Logger.getLogger(NotificationManager.class.getName())
                    .severe("The entity already exists!");
        }
    }
    
    /**
     * Updates the given notification
     * @param notification
     * @throws IllegalArgumentException if the notification doesn't exist
     */
    public void update(Notification notification){
        if(!exist(notification)){
            throw new IllegalArgumentException("The notification doesn't exist");
        } else{
            Calendar now = Calendar.getInstance();
            notification.setTimestamp(now);
            em.merge(notification);
        }
    }
    
    /**
     * Removes the notification from the database
     * @param notification
     */
    public void delete(Notification notification){
        em.remove(em.merge(notification));
    }
    
    /**
     * Retrieves all the notifications stored in the database.
     * @return the resulting list
     */
    public List<Notification> findAll(){
        Query query = em.createQuery("SELECT n FROM Notification n");
        try{
            List<Notification> notificationList = query.getResultList();
            return notificationList;
        }
        catch(NoResultException e){
            return null;
        }
    }
    
    /**
     * Searches all the notifications related to a given user.
     * @param user
     * @return the resulting list (may be null)
     */
    public List<Notification> findByUser(Users user){
        Query query = em.createQuery("SELECT n FROM Notification n "
                + "WHERE n.user = :user "
                + "ORDER BY n.timestamp DESC, n.seen");
        try{
            List<Notification> notificationList = (List<Notification>) query.setParameter("user", user)
                    .getResultList();
            return notificationList;
        }
        catch(NoResultException e){
            return null;
        }
    }
    
    /**
     * Searches all the notifications of the currently logged user.
     * @return the resulting list (may be null)
     */
    public List<Notification> findByLoggedUser(){
        Query query = em.createQuery("SELECT n FROM Notification n "
                + "WHERE n.user = :user "
                + "ORDER BY n.timestamp DESC, n.seen ASC");
        try{
            List<Notification> notificationList =  query.setParameter("user", um.getLoggedUser())
                    .getResultList();
            return notificationList;
        }
        catch(NoResultException e){
            return null;
        }
    }
    
     /**
     * Searches all the notifications related to a given event.
     * @param event
     * @return the resulting list (may be null)
     */
    public List<Notification> findByEvent(Event event){
        Query query = em.createQuery("SELECT n FROM Notification n WHERE n.event = :event");
        try{
            List<Notification> notificationList = (List<Notification>) query.setParameter("event", event)
                    .getResultList();
            return notificationList;
        }
        catch(NoResultException e){
            return null;
        }
    }
    
    /**
     * Searches all the notifications of a user related to a given event.
     * @param event
     * @param user
     * @return the resulting list (may be null)
     */
    public List<Notification> findByEventAndUser(Event event, Users user){
        Query query = em.createQuery("SELECT n FROM Notification n "
                + "WHERE n.event = :event "
                + "AND n.user = :user");
        try{
            List<Notification> notificationList = (List<Notification>) query.setParameter("event", event)
                    .setParameter("user", user)
                    .getResultList();
            return notificationList;
        }
        catch(NoResultException e){
            return null;
        }
    }

    /**
     * Checks if the given notification exists in the database
     * @param notification
     * @return true if it exists, false otherwise
     */
    private boolean exist(Notification notification) {
        return em.find(Notification.class, notification.getId()) != null;
    }
}
